#include <QMessageBox>
#include <QTextCodec>
#include <QClipboard>
#include <qsciscintilla.h>
#include <Scintilla.h>
#include "Version.h"
#include "Conversion.h"
#include "ConversionPannel.h"

const char* g_ctrlStr[] = {
	"NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL", "BS", "TAB",
	"LF", "VT", "FF", "CR", "SO", "SI", "DLE", "DC1", "DC2", "DC3",
	"DC4", "NAK", "SYN", "ETB", "CAN", "EM", "SUB", "ESC", "FS", "GS",
	"RS", "US"
};

ConversionPannel::ConversionPannel(MyQsciDoc &mydoc, QWidget* parent)
	:
	doc(mydoc),
	QWidget(parent)
{
	ui.setupUi(this);
	this->setWindowTitle(QString(PLUGIN_NAME) + " - Conversion");
	ui.pushButton->setShortcut(QKeySequence(PLUGIN_SHORTCUT_CVTPANNAL));
	ui.asciiEdit->setMaxLength(1);
	ui.hexEdit->setMaxLength(64);
	ui.decimalEdit->setMaxLength(64);
	ui.binaryEdit->setMaxLength(64);
	ui.octetEdit->setMaxLength(64);
}

ConversionPannel::~ConversionPannel()
{
}

void ConversionPannel::UpdateText(uint64_t val, int fromRadix)
{
	if (fromRadix != 0) {
		if (val <= 0xff) {
			auto txt = QByteArray(1, val);
			if (val > 31) {
				ui.asciiEdit->setText(QString::fromLatin1(txt));
				ui.asciiLabel->clear();
			} else {
				ui.asciiEdit->clear();
				ui.asciiLabel->setText(g_ctrlStr[val % 32]);
			}
		} else {
			ui.asciiEdit->clear();
			ui.asciiLabel->clear();
		}
	}
	if (fromRadix != 10) {
		auto decText = Converter::CharToIntStr(val, 10, true);
		ui.decimalEdit->setText(QString::fromLatin1(decText));
	}
	if (fromRadix != 16) {
		auto hexText = Converter::CharToIntStr(val, 16, true);
		ui.hexEdit->setText(QString::fromLatin1(hexText));
	}
	if (fromRadix != 2) {
		auto binaryText = Converter::CharToIntStr(val, 2, true);
		ui.binaryEdit->setText(QString::fromLatin1(binaryText));
	}
	if (fromRadix != 8) {
		auto octetText = Converter::CharToIntStr(val, 8, true);
		ui.octetEdit->setText(QString::fromLatin1(octetText));
	}
}

void ConversionPannel::SetReadOnly(bool readOnly)
{
	ui.asciiEdit->setReadOnly(readOnly);
	ui.hexEdit->setReadOnly(readOnly);
	ui.decimalEdit->setReadOnly(readOnly);
	ui.binaryEdit->setReadOnly(readOnly);
	ui.octetEdit->setReadOnly(readOnly);
	if (readOnly) {
		ui.asciiEdit->disconnect();
		ui.decimalEdit->disconnect();
		ui.hexEdit->disconnect();
		ui.binaryEdit->disconnect();
		ui.octetEdit->disconnect();
	}
	if (!readOnly) {
		QObject::connect(ui.asciiEdit, SIGNAL(textChanged(QString)), this, SLOT(AsciiChanged(QString)));
		QObject::connect(ui.decimalEdit, SIGNAL(textChanged(QString)), this, SLOT(DecimalChanged(QString)));
		QObject::connect(ui.hexEdit, SIGNAL(textChanged(QString)), this, SLOT(HexChanged(QString)));
		QObject::connect(ui.binaryEdit, SIGNAL(textChanged(QString)), this, SLOT(BinaryChanged(QString)));
		QObject::connect(ui.octetEdit, SIGNAL(textChanged(QString)), this, SLOT(OctetChanged(QString)));
	}
}

void ConversionPannel::Clear()
{
	ui.asciiEdit->clear();
	ui.hexEdit->clear();
	ui.decimalEdit->clear();
	ui.binaryEdit->clear();
	ui.hexEdit->clear();
	ui.octetEdit->clear();
}

void ConversionPannel::AsciiCopy()
{
	QApplication::clipboard()->setText(ui.asciiEdit->text());
}

void ConversionPannel::AsciiInsert()
{
	if (!doc.Valid()) {
		return;
	}
	doc->insert(ui.asciiEdit->text());
}

void ConversionPannel::DecimalCopy()
{
	QApplication::clipboard()->setText(ui.decimalEdit->text());
}

void ConversionPannel::DecimalInsert()
{
	if (!doc.Valid()) {
		return;
	}
	doc->insert(ui.decimalEdit->text());
}

void ConversionPannel::HexCopy()
{
	QApplication::clipboard()->setText(ui.hexEdit->text());
}

void ConversionPannel::HexInsert()
{
	if (!doc.Valid()) {
		return;
	}
	doc->insert(ui.hexEdit->text());
}

void ConversionPannel::BinaryCopy()
{
	QApplication::clipboard()->setText(ui.binaryEdit->text());
}

void ConversionPannel::BinaryInsert()
{
	if (!doc.Valid()) {
		return;
	}
	doc->insert(ui.binaryEdit->text());
}

void ConversionPannel::OctetCopy()
{
	QApplication::clipboard()->setText(ui.octetEdit->text());
}

void ConversionPannel::OctetInsert()
{
	if (!doc.Valid()) {
		return;
	}
	doc->insert(ui.octetEdit->text());
}

void ConversionPannel::AsciiChanged(QString text)
{
	SetReadOnly(true);
	if (text.isEmpty()) {
		Clear();
		SetReadOnly(false);
		return;
	}
	if (text.at(0) > 255 || text.at(0) < 0) {
		ui.asciiEdit->setText(lastAsciiStr);
		SetReadOnly(false);
		return;
	}
	UpdateText(*text.toStdString().c_str(), 0);
	lastAsciiStr = text;
	SetReadOnly(false);
}

void ConversionPannel::DecimalChanged(QString text)
{
	SetReadOnly(true);
	if (text.isEmpty()) {
		Clear();
		SetReadOnly(false);
		return;
	}
	bool ok = true;
	auto val = text.toULong(&ok, 10);
	if (!ok) {
		ui.decimalEdit->setText(lastDecimalStr);
		SetReadOnly(false);
		return;
	}
	UpdateText(val, 10);
	lastDecimalStr = text;
	SetReadOnly(false);
}

void ConversionPannel::HexChanged(QString text)
{
	SetReadOnly(true);
	if (text.isEmpty()) {
		Clear();
		SetReadOnly(false);
		return;
	}
	bool ok = true;
	auto val = text.toULong(&ok, 16);
	if (!ok) {
		ui.hexEdit->setText(lastHexStr);
		SetReadOnly(false);
		return;
	}
	UpdateText(val, 16);
	lastHexStr = text;
	SetReadOnly(false);
}

void ConversionPannel::BinaryChanged(QString text)
{
	SetReadOnly(true);
	if (text.isEmpty()) {
		Clear();
		SetReadOnly(false);
		return;
	}
	bool ok = true;
	auto val = text.toULong(&ok, 2);
	if (!ok) {
		ui.binaryEdit->setText(lastBinaryStr);
		SetReadOnly(false);
		return;
	}
	UpdateText(val, 2);
	lastBinaryStr = text;
	SetReadOnly(false);
}

void ConversionPannel::OctetChanged(QString text)
{
	SetReadOnly(true);
	if (text.isEmpty()) {
		Clear();
		SetReadOnly(false);
		return;
	}
	bool ok = true;
	auto val = text.toULong(&ok, 8);
	if (!ok) {
		ui.octetEdit->setText(lastOctetStr);
		SetReadOnly(false);
		return;
	}
	UpdateText(val, 8);
	lastOctetStr = text;
	SetReadOnly(false);
}

